package com.tensquare.user.service;

import java.util.*;
import java.util.concurrent.TimeUnit;
import javax.persistence.criteria.Predicate;

import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.redis.core.ReactiveRedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import org.springframework.transaction.annotation.Transactional;
import utils.IdWorker;

import com.tensquare.user.dao.UserRepository;
import com.tensquare.user.po.User;

/**
 * 服务层
 *
 * @author Administrator
 */
@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private IdWorker idWorker;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RabbitTemplate rabbitTemplate;


    /**
     * 修改
     *
     * @param user
     */
    public void updateUser(User user) {
        userRepository.save(user);
    }

    /**
     * 删除
     *
     * @param id
     */
    public void deleteUserById(String id) {
        userRepository.deleteById(id);
    }

    /**
     * 查询全部列表
     *
     * @return
     */
    public List<User> findUserList() {
        return userRepository.findAll();
    }

    /**
     * 根据ID查询实体
     *
     * @param id
     * @return
     */
    public User findUserById(String id) {
        return userRepository.findById(id).get();
    }

    /**
     * 根据条件查询列表
     *
     * @param whereMap
     * @return
     */
    public List<User> findUserList(Map whereMap) {
        //构建Spec查询条件
        Specification<User> specification = getUserSpecification(whereMap);
        //Specification条件查询
        return userRepository.findAll(specification);
    }

    /**
     * 组合条件分页查询
     *
     * @param whereMap
     * @param page
     * @param size
     * @return
     */
    public Page<User> findUserListPage(Map whereMap, int page, int size) {
        //构建Spec查询条件
        Specification<User> specification = getUserSpecification(whereMap);
        //构建请求的分页对象
        PageRequest pageRequest = PageRequest.of(page - 1, size);
        return userRepository.findAll(specification, pageRequest);
    }

    /**
     * 根据参数Map获取Spec条件对象
     *
     * @param searchMap
     * @return
     */
    private Specification<User> getUserSpecification(Map searchMap) {

        return (Specification<User>) (root, query, cb) -> {
            //临时存放条件结果的集合
            List<Predicate> predicateList = new ArrayList<Predicate>();
            //属性条件
            // ID
            if (searchMap.get("id") != null && !"".equals(searchMap.get("id"))) {
                predicateList.add(cb.like(root.get("id").as(String.class), "%" + (String) searchMap.get("id") + "%"));
            }
            // 手机号码
            if (searchMap.get("mobile") != null && !"".equals(searchMap.get("mobile"))) {
                predicateList.add(cb.like(root.get("mobile").as(String.class), "%" + (String) searchMap.get("mobile") + "%"));
            }
            // 密码
            if (searchMap.get("password") != null && !"".equals(searchMap.get("password"))) {
                predicateList.add(cb.like(root.get("password").as(String.class), "%" + (String) searchMap.get("password") + "%"));
            }
            // 昵称
            if (searchMap.get("nickname") != null && !"".equals(searchMap.get("nickname"))) {
                predicateList.add(cb.like(root.get("nickname").as(String.class), "%" + (String) searchMap.get("nickname") + "%"));
            }
            // 性别
            if (searchMap.get("sex") != null && !"".equals(searchMap.get("sex"))) {
                predicateList.add(cb.like(root.get("sex").as(String.class), "%" + (String) searchMap.get("sex") + "%"));
            }
            // 头像
            if (searchMap.get("avatar") != null && !"".equals(searchMap.get("avatar"))) {
                predicateList.add(cb.like(root.get("avatar").as(String.class), "%" + (String) searchMap.get("avatar") + "%"));
            }
            // E-Mail
            if (searchMap.get("email") != null && !"".equals(searchMap.get("email"))) {
                predicateList.add(cb.like(root.get("email").as(String.class), "%" + (String) searchMap.get("email") + "%"));
            }
            // 兴趣
            if (searchMap.get("interest") != null && !"".equals(searchMap.get("interest"))) {
                predicateList.add(cb.like(root.get("interest").as(String.class), "%" + (String) searchMap.get("interest") + "%"));
            }
            // 个性
            if (searchMap.get("personality") != null && !"".equals(searchMap.get("personality"))) {
                predicateList.add(cb.like(root.get("personality").as(String.class), "%" + (String) searchMap.get("personality") + "%"));
            }

            //最后组合为and关系并返回
            return cb.and(predicateList.toArray(new Predicate[predicateList.size()]));
        };

    }

    /**
     * 发送短信验证码（保存手机验证码到redis中）
     *
     * @param mobile
     */
    private final static String PREXFIX_REDIS = "sms_checkCode_";

    public void saveSmsCheckcode(String mobile) {
        // 1. 生成六位数随机验证码
        String checkCode = RandomStringUtils.randomNumeric(6);
        System.out.println("生成验证码:" + checkCode);
        // 2. 保存到redis中
        this.redisTemplate.opsForValue().set(PREXFIX_REDIS + mobile, checkCode, 5, TimeUnit.MINUTES);

        // 3. 将手机验证码发送到RabbitMq中
        HashMap<String, String> map = new HashMap<>();
        map.put("checkcode", checkCode);
        map.put("mobile", mobile);
//        this.rabbitTemplate.convertAndSend("sms.checkcode", map);

    }

    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    /**
     * 注册用户，需要验证码校验
     */
    public void saveUser(User user, String checkCode) {
        // 获取验证码
        String realCheckCode = (String) this.redisTemplate.opsForValue().get(PREXFIX_REDIS + user.getMobile());
        // 校验redis是否有该用户的验证码
        if (StringUtils.isBlank(realCheckCode)) {
            // 为空，未获取验证码, 抛错
            throw new RuntimeException("请点击获取验证码");
        }
        // 校验验证码是否匹配
        if (!StringUtils.equals(realCheckCode, checkCode)) {
            // 验证码错误
            throw new RuntimeException("验证码错误");
        }

        //2. 设置默认值，并保存
        user.setId(idWorker.nextId() + "");
        user.setFollowcount(0);//关注数
        user.setFanscount(0);//粉丝数
        user.setOnline(0L);//在线时长
        user.setRegdate(new Date());//注册日期

        // 加密
        String newPassword = this.bCryptPasswordEncoder.encode(user.getPassword());
        user.setPassword(newPassword);
        // 保存用户
        this.userRepository.save(user);
        // 删除缓存中的验证码
        this.redisTemplate.delete(PREXFIX_REDIS + user.getMobile());

    }

    /**
     * 根据手机和密码进行查询
     * 登陆使用
     */
    public User findByMobileAndPassword(String mobile, String password) {
        // 根据手机号查询对象
        User user = this.userRepository.findByMobile(mobile);
        if (user != null && this.bCryptPasswordEncoder.matches(password, user.getPassword())) {
            // 用户存在就直接返回user
            return user;
        }
        return null;
    }


    /**
     * 更新添加好友的粉丝数。同时增加自己的关注数
     * 因为是提供给后台调用的，所以不需要返回值
     */
    @Transactional // 添加事务
    public void updateFansCountAndFollowCount(String userid, String friendid, int x) {
        // 增加/减少自己的关注数
        this.userRepository.incFollowCount(userid, x);
        // 增加/减少对方好友的粉丝数jk
        this.userRepository.incFansCount(friendid, x);
    }
}
